﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Runtime.Remoting;
using EasyHook;
using System.Diagnostics;
using System.Collections.Generic;

namespace SqlMon
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        static String ChannelName = null;
        const int TIMER_INTERVAL = 1000  * 30;//30秒
        System.Timers.Timer processTimer = new System.Timers.Timer(TIMER_INTERVAL);//更新进程列表定时器
        const int SQL_INTERVAL = 1000;//1秒
        System.Timers.Timer sqlinfoTimer = new System.Timers.Timer(SQL_INTERVAL);//更新sql列表定时器
        public static Queue<string> sqlQueue = new System.Collections.Generic.Queue<string>();//sql队列 供SqlMonInterface访问
        static int HookPID = -1;//当前Hook的Procees ID

        private void MainForm_Load(object sender, EventArgs e)
        {
            try
            {
                //加入到GAC
                Config.Register(
                    "DIY SqlMonitor",
                    "SqlMon.exe",//本程序名
                    "SqlMonInject.dll");//注入DLL名
            }
            catch (ApplicationException)
            {
                MessageBox.Show("需要管理员权限!", "权限不足...", MessageBoxButtons.OK);

                //System.Diagnostics.Process.GetCurrentProcess().Kill();
                return;
            }

            //SqlMonInterface未自定义的操作接口类 
            RemoteHooking.IpcCreateServer<SqlMonInterface>(ref ChannelName, WellKnownObjectMode.SingleCall);

            processTimer.Elapsed += new System.Timers.ElapsedEventHandler((o,eea) =>
            {
                FreshProcess();
            });
            processTimer.Start();

            sqlinfoTimer.Elapsed += new System.Timers.ElapsedEventHandler(sqlinfoTimer_Elapsed);
        }

        void sqlinfoTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            //while (sqlQueue.Count > 0)
            //{
                string sql = sqlQueue.Dequeue();
                rtbSqlInfo.AppendText("************" + DateTime.Now.ToLongTimeString() + "************" + Environment.NewLine);
                rtbSqlInfo.AppendText(sql + Environment.NewLine + Environment.NewLine);//添加显示
            //}
        }

        private void tsmClose_Click(object sender, EventArgs e)
        {
            //退出
            Environment.Exit(Environment.ExitCode);
        }

        /// <summary>
        /// 取调用OCI的进程列表，加载到clbProcess列表中
        /// </summary>
        private IList<Process> GetOCIProcess()
        {
            Process[] pros = Process.GetProcesses();//取所有进程
            IList<Process> listProcess = new List<Process>(5);

            foreach (Process pro in pros)
            {
                if (pro.ProcessName != "plsqldev")
                    continue;

                //循环每个进程，是否存在OCI.DLL的模块
                foreach (ProcessModule pm in pro.Modules)
                {
                    //判断FileName更准确 TODO...
                    if (pm.ModuleName.Trim().ToUpper() == "OCI.DLL")
                    {
                        listProcess.Add(pro);
                    }
                }
            }
            return listProcess;
        }

        private void FreshProcess()
        {
            clbProcess.Items.Clear();
            IList<Process> listPro = GetOCIProcess();
            foreach (Process pro in listPro)
            {
                clbProcess.Items.Add(pro.ProcessName + "(" + pro.Id + ")");
                if (pro.Id == HookPID)
                {
                    clbProcess.SetSelected(clbProcess.Items.Count - 1, true);
                    clbProcess.SetItemChecked(clbProcess.Items.Count - 1, true);
                }
            }
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            FreshProcess();
        }

        private void clbProcess_SelectedIndexChanged(object sender, EventArgs e)
        {        
        }

        //注入进程
        private void InjectProcess(string processId)
        {
            int pid;
            try{
                pid = int.Parse(processId);
                if (pid == HookPID)
                    return;
                else
                    HookPID = pid;
            }
            catch{
                MessageBox.Show("取进程ID出错","错误信息",MessageBoxButtons.OK);
                return;
            }         

            //远程注入
            RemoteHooking.Inject(
                HookPID,//进程ID
                "SqlMonInject.dll",//32位dll
                "SqlMonInject.dll",//64位dll
                ChannelName);
        }

        private void clbProcess_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (e.NewValue == CheckState.Checked)
            {
                clbProcess.SetSelected(e.Index, true);

                if (clbProcess.SelectedItem != null)
                {
                    lock (sqlQueue)
                        sqlQueue.Clear();
                    //rtbSqlInfo.Clear();//sql列表清空

                    string selectPro = clbProcess.SelectedItem.ToString();
                    //取进程ID  Processname(ID)
                    int startIndex = selectPro.LastIndexOf('(');
                    string processId = selectPro.Substring(startIndex + 1, selectPro.Length - startIndex - 2);
                    InjectProcess(processId);

                    sqlinfoTimer.Start();//启动sql定时器
                }
            }
            else
            {
                sqlinfoTimer.Stop();
            }
        }
    }
}
